#pragma once
#include "sock.hpp"
#include <unistd.h>
#include <vector>

#define DEFAULTPORT 8080
#define ANYIP "0.0.0.0"
#define FDNUMS sizeof(fd_set) * 8

typedef std::string(*fun_t)(std::string);

namespace ServerFile
{

    class Server
    {
        void HandlerAccept()
        {
            // 说明已经准备好，可以提取accept了
            std::string ClinetIP;
            uint16_t ClinetPort;
            int sock = Sock::Accpet(_listensock, ClinetIP, ClinetPort);

            if (sock < 0)
                return;

            if (sock > 0)
            {
                // 若sock > 0 那么后续sock要关注读写，所以我们把sock加入到 _fdnums中
                int i = 0;
                for (; i < FDNUMS; i++)
                    if (_fdnums[i] == -1)
                        break;

                if (i == FDNUMS)
                    std::cout << "可监管的sock套接字已满，请稍等业务处理之后再来吧" << std::endl;
                else
                {
                    _fdnums[i] = sock;
                    std::cout << "sock已经被设置到select中" << std::endl;
                }
            }
        }

        void HandlerRead(int sock , int pos)
        {
             //我要申明一下这里不能确保读到一个报文，要确保读到一个报文那得 约定报头，while循环读取
             char buffer[1024];
             ssize_t s = read(sock,buffer,sizeof buffer - 1);

             if(s > 0)
             {
                buffer[s-1] = 0;
                //std::cout << buffer << std::endl;
             }
             else if(s == 0)
             {
                //表示对端关闭写,我们也关闭读取了
                close(sock);
                _fdnums[pos] = -1;
             }
             else
             {
                logMessage(FATAL);
                exit(READ_ERRON);
             }

             //到这里我们得处理读取上来的数据了
             std::string response = _fun(buffer);

             int n = write(sock,response.c_str(),response.size()); 
             if(n < 0)
             {
                logMessage(WARNING);
                std::cout << "处理后response字符串为空,你将要给对方回复空消息" << std::endl;
             }

        }

        void HandlerTask(fd_set &fds)
        {
            //能走到这里代表有就绪的套接字
            for (int i = 0; i < FDNUMS; i++)
            {
                if( FD_ISSET(_fdnums[i],&fds) && _fdnums[i] == _listensock)
                 HandlerAccept();
                else if(FD_ISSET(_fdnums[i],&fds))
                 HandlerRead(_fdnums[i],i);

            }
        }

    public:
        Server(fun_t fun_t,uint16_t port = DEFAULTPORT)
            : _port(port)
            , _fun(fun_t)
        {
            _fdnums = std::vector<int>(FDNUMS, -1); // 表示给fdnums初始化大小
        }

        // 创建监听套接字，bind链接，设置listen监听
        void init()
        {
            _listensock = Sock::SetSocket();
            Sock::Bind(_listensock, ANYIP, _port);
            Sock::Listen(_listensock);

            _fdnums[0] = _listensock;
            // std::cout << _listensock << std::endl;
        }

        void start()
        {
            // 开始accpet，等待accpet返回大于0的套接字，从accpte开始就有等的步骤了，要用select了
            for (;;)
            {
                fd_set fds;
                FD_ZERO(&fds);
                int maxfd = -1;
                for (int i = 0; i < FDNUMS; i++)
                {
                    if (_fdnums[i] != -1)
                        FD_SET(_fdnums[i], &fds);

                    maxfd = std::max(maxfd, _fdnums[i]);
                }

                //std::cout << maxfd << std::endl;
                if (maxfd == -1)
                {
                    logMessage(FATAL);
                    exit(SELECTNORESOURSE);
                }

                // struct timeval times = {5, 0}; // 第一个表示秒,第二个表示毫秒
                int n = select(maxfd + 1, &fds, nullptr, nullptr, nullptr);
                if (n > 0)
                {
                    // 说明listen就绪了，有人accept了,fds已经被修改
                    HandlerTask(fds);
                    // std::cout << "我知道listensock就绪，但是我就是不把accept拿上去，这个会一直打印的吧" << std::endl;
                    // usleep(1000);
                }
                else if (n == 0)
                {
                    std::cout << "要关注的listensock任然没有就绪" << std::endl;
                    continue;
                }
                else
                {
                    logMessage(FATAL);
                    exit(SELECT_ERRON);
                }
            }
        }

        ~Server()
        {
            if (_listensock > 0)
                close(_listensock);
            // vector自己会析构
        }

    private:
        // 需要套接字和端口号
        int _listensock;
        uint16_t _port;
        std::vector<int> _fdnums;
        fun_t _fun;
    };
}